package com.qf.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qf.common.PageVO;
import com.qf.entity.product.Product;
import com.qf.entity.product.ProductReview;
import com.qf.entity.product.ProductReviewLikeDislike;
import com.qf.mapper.ProductMapper;
import com.qf.mapper.ProductReviewLikeDislikeMapper;
import com.qf.mapper.ProductReviewMapper;
import com.qf.param.DTO.ProductAddDTO;
import com.qf.param.DTO.ProductListPageDTO;
import com.qf.param.DTO.ProductUpdateDTO;
import com.qf.param.VO.ProductInfoVO;
import com.qf.param.VO.ProductListPageVO;
import com.qf.service.ProductService;
import com.qf.commom.minio.utils.MinioUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author Ayases
 * @Date 2025/6/9 15:21
 * @Desc
 */

@Service
public class ProductServiceImpl implements ProductService {


    // 日志对象
    private static final Logger log = LoggerFactory.getLogger(ProductServiceImpl.class);

    @Resource
    private ProductMapper productMapper;

    @Resource
    private ProductReviewMapper productReviewMapper;

    @Resource
    private ProductReviewLikeDislikeMapper productReviewLikeDislikeMapper;

    @Resource
    private MinioUtil minioUtil;


    /**
     * 商品分页查询
     * 逻辑：
     * 1. 创建分页对象，基于前端传入的分页参数
     * 2. 执行分页查询：只查询status=1(已上架)的商品信息
     * 3. 获取查询到的商品列表
     * 4. 将Product列表转换为ProductListPageVO列表，处理一部分数据
     * 5. 构造分页返回对象
     *
     * @param productInfoDTO
     * @return
     */
    @Override
    public PageVO<ProductListPageVO> productPageInfo(ProductListPageDTO productInfoDTO) {
        // 1. 创建分页对象，基于前端传入的分页参数
        Page<Product> page = new Page<>(productInfoDTO.getPageNum(), productInfoDTO.getPageSize());

        // 2. 执行分页查询：只查询status=1(已上架)的商品信息
        page = productMapper.selectPage(page, Wrappers.lambdaQuery(Product.class)
                .eq(Product::getStatus, 1));

        // 3. 获取查询到的商品列表
        List<Product> records = page.getRecords();

        // 4. 将Product列表转换为ProductListPageVO列表，处理一部分数据
        List<ProductListPageVO> voList = records.stream().map(product -> {
            ProductListPageVO vo = new ProductListPageVO();
            // 设置ID（假设Product中的id是Long类型，转换为String）
            vo.setId(String.valueOf(product.getId()));
            vo.setName(product.getName());
            vo.setPrice(product.getPrice());

            // 处理封面图：取第一张图片
            if (StringUtils.isNotBlank(product.getImageUrls())) {
                String[] images = product.getImageUrls().split(",");
                vo.setCoverImg(images[0]); // 取第一张作为封面
            }

            // 设置分类（这里假设Product中有getCategoryName方法）
            vo.setCategory(product.getCategory());

            return vo;
        }).collect(Collectors.toList());

        // 5. 构造分页返回对象
        PageVO<ProductListPageVO> pageVO = new PageVO<>();
        pageVO.setTotal(page.getTotal());       // 总记录数
        pageVO.setDataList(voList);             // 当前页数据列表

        return pageVO;
    }


    /**
     * 获取商品详情信息
     * 逻辑：
     * 1. 根据ID查询商品信息
     * 2. 将Product转换为ProductInfoVO，处理一部分数据ImageUrls
     * 3. 将图片字符串转换为List<String>
     *
     * @param id
     * @return
     */
    @Override
    public Object getProductInfo(String id) {
        // 1. 根据ID查询商品信息
        Product product = productMapper.selectById(id);

        // 2. 将Product转换为ProductInfoVO，处理一部分数据ImageUrls
        ProductInfoVO vo = new ProductInfoVO();
        BeanUtils.copyProperties(product, vo);

        // 3. 将图片字符串转换为List<String>
        if (StringUtils.isNotBlank(product.getImageUrls())) {
            String[] images = product.getImageUrls().split(",");
            vo.setImageUrls(Arrays.asList(images));
        }

        return vo;
    }


    /**
     * 添加商品
     * 逻辑：
     * 1. 上传图片到MinIO并获取URL列表
     * 2. 转换DTO为Product实体
     * 3. 保存到数据库
     * 4. 处理异常：上传失败时抛出运行时异常
     * 5. 返回成功信息
     *
     * @param productAddDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)// 事务注解，用于事务回滚
    public void addProduct(ProductAddDTO productAddDTO) {
        // 1. 上传图片到MinIO并获取URL列表
        List<String> imageUrlList = new ArrayList<>();
        if (productAddDTO.getImageUrls() != null && productAddDTO.getImageUrls().length > 0) {
            for (MultipartFile file : productAddDTO.getImageUrls()) {
                if (!file.isEmpty()) {
                    try {
                        // 1.1 获取原始文件名（包含扩展名）
                        String originalFilename = file.getOriginalFilename();

                        // 1.2 生成唯一文件名：UUID + 文件扩展名
                        String uuid = UUID.randomUUID().toString().replace("-", "");
                        String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
                        String uniqueFilename = uuid + extension;

                        // 1.3 上传到MinIO并获取访问URL
                        String fileUrl = minioUtil.upload(uniqueFilename, file.getInputStream());
                        imageUrlList.add(fileUrl);

                    } catch (IOException e) {
                        // 上传失败时抛出运行时异常（可根据业务需求自定义异常）
                        throw new RuntimeException("图片上传失败: " + e.getMessage(), e);
                    }
                }
            }
        }

        // 2. 转换DTO为Product实体
        Product product = new Product();

        // 2.1 设置基础信息
        product.setId(UUID.randomUUID().toString().replace("-", "")); // 32位UUID主键
        product.setSku(productAddDTO.getSku());
        product.setName(productAddDTO.getName());
        product.setPrice(productAddDTO.getPrice());
        product.setCategory(productAddDTO.getCategory());
        product.setDescription(productAddDTO.getDescription());

        // 2.2 拼接图片URL（逗号分隔）
        product.setImageUrls(String.join(",", imageUrlList));

        // 2.3 设置库存/销售/状态（DTO无销售字段，默认0）
        product.setStock(productAddDTO.getStock() != null ? productAddDTO.getStock() : 0);
        product.setSales(0); // 新增商品销售量为0
        product.setStatus(productAddDTO.getStatus());

        // 2.4 设置时间戳
        LocalDateTime now = LocalDateTime.now();
        product.setCreatedAt(now);
        product.setUpdatedAt(now);

        // 3. 保存到数据库
        productMapper.insert(product);
    }

    /**
     * 更新商品核心逻辑
     * 执行步骤：
     * 1. 参数校验（由Spring Validation处理）
     * 2. 查询现有商品（不存在则抛出异常）
     * 3. 图片更新处理：
     * a) 新图片上传到MinIO
     * b) 删除旧图片（如果存在且需要更新）
     * 4. 非空字段更新（使用BeanUtils忽略空值）
     * 5. 设置更新时间戳
     * 6. 执行数据库更新
     *
     * @param updateDTO 更新数据传输对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProduct(ProductUpdateDTO updateDTO) {
        // 1. 查询现有商品
        Product existingProduct = productMapper.selectById(updateDTO.getId());
        if (existingProduct == null) {
            throw new RuntimeException("商品不存在，ID: " + updateDTO.getId());
        }

        // 2. 图片更新处理
        List<String> newImageUrls = new ArrayList<>();

        // 情况1：上传了新图片（包含空数组）
        if (updateDTO.getImageUrls() != null) {
            // 2.1 删除旧图片（如果存在）
            String oldImageUrls = existingProduct.getImageUrls();
            if (StringUtils.isNotBlank(oldImageUrls)) {
                Arrays.stream(oldImageUrls.split(",")).forEach(url -> {
                    try {
                        // 从URL中解析出对象名（格式：http://endpoint/bucket/object）
                        String objectName = url.substring(url.lastIndexOf("/") + 1);
                        minioUtil.delete(objectName); // 调用MinIO删除方法
                    } catch (Exception e) {
                        log.error("旧图片删除失败: {}", url, e);
                    }
                });
            }

            // 2.2 上传新图片（空数组时不执行上传）
            for (MultipartFile file : updateDTO.getImageUrls()) {
                if (!file.isEmpty()) {
                    try {
                        // 生成唯一文件名并上传
                        String originalFilename = file.getOriginalFilename();
                        String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
                        String uniqueFilename = UUID.randomUUID() + extension;
                        String fileUrl = minioUtil.upload(uniqueFilename, file.getInputStream());
                        newImageUrls.add(fileUrl);
                    } catch (IOException e) {
                        throw new RuntimeException("图片上传失败: " + e.getMessage(), e);
                    }
                }
            }
            existingProduct.setImageUrls(String.join(",", newImageUrls));
        }

        // 3. 复制非空属性（获取null字段名）
        Set<String> emptyNames = new HashSet<>();
        BeanWrapper srcWrapper = new BeanWrapperImpl(updateDTO);
        for (PropertyDescriptor pd : srcWrapper.getPropertyDescriptors()) {
            Object val = srcWrapper.getPropertyValue(pd.getName());
            if (val == null) emptyNames.add(pd.getName());
        }
        String[] ignoreProperties = emptyNames.toArray(new String[0]);

        // 4. 执行属性拷贝（忽略null值）
        BeanUtils.copyProperties(updateDTO, existingProduct, ignoreProperties);

        // 5. 更新审计字段
        existingProduct.setUpdatedAt(LocalDateTime.now());

        // 6. 执行数据库更新
        productMapper.updateById(existingProduct);
    }

    /**
     * 删除商品
     * 逻辑：
     * 1. 验证商品是否存在
     * 2. 查询商品关联的所有评价
     * 3. 删除评价关联的点赞点踩记录
     * 4. 删除评价记录本身
     * 5. 删除商品记录
     * 6. 清理MinIO中的图片文件（商品和评价图片）
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteProduct(String id) {
        // 1. 验证商品是否存在
        Product product = productMapper.selectById(id);
        if (product == null) {
            throw new RuntimeException("商品不存在，ID: " + id);
        }

        // 2. 查询商品关联的所有评价
        QueryWrapper<ProductReview> reviewQuery = new QueryWrapper<>();
        reviewQuery.eq("product_id", id);
        List<ProductReview> reviews = productReviewMapper.selectList(reviewQuery);
        List<String> reviewIds = reviews.stream()
                .map(ProductReview::getId)
                .collect(Collectors.toList());

        // 3. 删除评价关联的点赞点踩记录
        if (!reviewIds.isEmpty()) {
            QueryWrapper<ProductReviewLikeDislike> likeDislikeQuery = new QueryWrapper<>();
            likeDislikeQuery.in("review_id", reviewIds);
            productReviewLikeDislikeMapper.delete(likeDislikeQuery);
        }

        // 4. 删除评价记录本身
        if (!reviewIds.isEmpty()) {
            productReviewMapper.deleteBatchIds(reviewIds);
        }

        // 5. 删除商品记录
        productMapper.deleteById(id);

        // 6. 清理MinIO中的图片文件（商品和评价图片）
        // --- 原deleteProductImages方法内联至此 ---
        // 6.1 删除商品主图
        deleteImagesFromMinio(product.getImageUrls());

        // 6.2 遍历删除所有评价图片
        for (ProductReview review : reviews) {
            deleteImagesFromMinio(review.getImageUrls());
        }
        // --- 内联完成 ---
    }

    /**
     * 从MinIO删除图片URL列表（保持不变，因复用性保留独立方法）
     *
     * @param imageUrls 逗号分隔的图片URL列表
     */
    private void deleteImagesFromMinio(String imageUrls) {
        if (StringUtils.isBlank(imageUrls)) {
            return;
        }
        Arrays.stream(imageUrls.split(","))
                .filter(StringUtils::isNotBlank)
                .forEach(url -> {
                    try {
                        String objectName = url.substring(url.lastIndexOf("/") + 1);
                        minioUtil.delete(objectName);
                    } catch (Exception e) {
                        log.error("MinIO图片删除失败: {}", url, e);
                    }
                });
    }


}




